# -*- coding: utf-8 -*-
# &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
# Odoo Connector
# QQ:978979209
# Author：'zengfajun'
# Date：2018-06-06
# &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

import logging
from datetime import datetime
from odoo import models, fields, api
from odoo.tools import safe_eval
from odoo.exceptions import ValidationError


logger = logging.getLogger(__name__)


class AccountBankStatementExtend(models.Model):
    _inherit = 'account.bank.statement'

    balance_end_real = fields.Monetary('Ending Balance', store=True,
                                        compute="_compute_xdl_balance_end_real",
                                       states={'confirm': [('readonly', True)]})
    xdl_line_count = fields.Monetary('总计', store=True,
                                     compute="_compute_xdl_line_count")
    bank_acc_number = fields.Char('银行账号', related="journal_id.bank_acc_number", store=True)

    @api.depends('xdl_line_count', 'balance_start')
    def _compute_xdl_balance_end_real(self):
        for order in self:
            order.balance_end_real = order.xdl_line_count + order.balance_start

    @api.depends('line_ids.amount')
    def _compute_xdl_line_count(self):
        for order in self:
            order.xdl_line_count = sum(order.line_ids.mapped('amount'))

    # 银行生成收款单方法
    @api.multi
    def create_payment_line(self):
        # 确保单例操作
        self.ensure_one()
        payment_obj = self.env['account.payment']

        for record in self.line_ids:
            # 根据金额符号，获取支付方法
            total = record.amount

            payment_type = False
            partner_type = False
            account = False
            # 客户需求：只有金钱和客户字段都有值时，未生成收款单的子表数据生成对应的的收款单
            # if (record.partner_id and record.amount and not record.journal_entry_ids) or (
            #         record.statement_class.name in [u'手续费', u'利息', u'其它'] and not record.journal_entry_ids):
            if record.statement_class.name in ['应收', '应付'] and not (record.partner_id and record.amount):
                continue
            if not record.journal_entry_ids:
                # 生产收款单
                line_partner_type = record.line_partner_type
                if line_partner_type:
                    if total > 0:
                        partner_type = line_partner_type
                        payment_type = 'inbound'
                    else:
                        partner_type = line_partner_type
                        payment_type = 'outbound'
                else:
                    if total > 0:
                        partner_type = 'customer'
                        payment_type = 'inbound'
                    else:
                        partner_type = 'supplier'
                        payment_type = 'outbound'

                    # 为咨询费时，需要设置其科目为客户的会计分录的应收款科目
                    if record.partner_id.customer:
                        partner_type = 'customer'
                    if record.partner_id.supplier:
                        partner_type = 'supplier'

            # elif record.employee_id and not record.journal_entry_ids:
            #     # 为员工借还款时，需要设置其科目为员工的借还款科目
            #     payment_type = total > 0 and 'refund' or 'loan'
            #     partner_type = False
            #     if not record.employee_id.account_id:
            #         raise ValidationError(u'请先设置员工的借还款科目！')
            account = record.debit_account_id or record.credit_account_id
            if not account:
                raise ValidationError('请设置借贷科目，借贷科目不能都为空')
            if payment_type:
                record._create_payment(payment_type=payment_type,
                                     partner_type=partner_type,
                                     payment_amount=total,
                                     account=account)

    @api.multi
    def button_account_payment(self):
        context = dict(self._context or {})
        context['journal_id'] = self.journal_id.id
        return {
            'name': u'收款信息',
            'view_type': 'form',
            'view_mode': 'tree,form',
            'res_model': 'account.payment',
            'view_id': False,
            'type': 'ir.actions.act_window',
            'domain': [('id', 'in', self.mapped('move_line_ids').mapped('payment_id').ids)],
            'context': context,
        }


class AccountBankStatementLineExtend(models.Model):
    _inherit = 'account.bank.statement.line'

    is_cost = fields.Boolean(string=u'是否为咨询费', default=False)
    employee_id = fields.Many2one('hr.employee', string=u'员工')
    statement_class = fields.Many2one('account.statement.line.class', string="类型", required=True)
    debit_account_id = fields.Many2one('account.account', string='借方科目')  
    credit_account_id = fields.Many2one('account.account', string='贷方科目')
    bank_note = fields.Char(string=u'对方账号名称')
    salesman_id = fields.Many2one('res.users', string=u'销售员')
    salesman_date = fields.Datetime(string=u'确认时间')
    flag = fields.Selection([
        ('debit', '借方'),
        ('credit', '贷方') ], related="statement_class.used", store=True)
    origin_record = fields.Char(string=u'对方账号名称')
    xdl_bank_name = fields.Char('银行', related="statement_id.journal_id.name", store=True)
    line_partner_type = fields.Selection([
        ('customer', '客户'),
        ('supplier', '供应商'),
        ('other', '其他')], '合作伙伴类型', required=True)

    @api.onchange('statement_class')
    def _onchange_xdl_account_id(self):
        # 根据类型，自动带出科目
        for line in self:
            statement_class = line.statement_class
            if statement_class.used == 'debit':
                line.debit_account_id = statement_class.account_id
            elif statement_class.used == 'credit':
                line.credit_account_id = statement_class.account_id

    @api.multi
    def button_cancel_reconciliation(self):
        # 要提前记录这些单据，不然系统的方法就会断开这些联系，就没办法找到了
        account_move_line = self.env['account.move.line'].search([('statement_line_id', '=', self.id)])
        account_payments = self.env['account.payment'].search([('move_line_ids', 'in', account_move_line.ids)])

        res = super(AccountBankStatementLineExtend, self).button_cancel_reconciliation()
        # 删除相应的日记分录和收款单
        self.xdl_delete_account_move_Line(account_move_line, account_payments)
        return res

    def xdl_delete_account_move_Line(self, account_move_line, account_payments):
        # account_move_line：account.move.line：与待反核销的银行对账单明细 相对应的 日记账分录明细
        # account_payments： account.payment: 与待反核销的银行对账单明细 相对应的 收款单

        # 删除对应的日记账分录, 通过日记账明细来寻找到日记账
        account_move = account_move_line.mapped('move_id')
        if account_move and account_move.state == 'posted':
            # 遇到已核销的分录，就“取消分录”
            logger.info('尝试对日记账分录“%s”执行“取消分录”操作！'%account_move.name)
            account_move.button_cancel()
            logger.info('成功“取消分录”了日记账分录“%s”' % account_move.name)
        account_move_line.sudo().unlink()

        account_move_name = account_move.name
        logger.info('尝试删除日记账分录“%s”' % account_move_name)
        account_move.sudo().unlink()
        logger.info('成功删除日记账分录“%s”' % account_move_name)

        if account_payments:
            for i in account_payments:
                i.write({'move_name': ''})
            account_payments.cancel()
            payment_name = account_payments.name
            logger.info('尝试删除收/付款单“%s”' % payment_name)
            account_payments.sudo().unlink()
            logger.info('成功删除收/付款单“%s”' % payment_name)

        # account_move_line2 = self.env['account.move.line'].search([('payment_id', 'in', account_payments.ids)])

    @api.multi
    def _create_payment(self, payment_type, partner_type, payment_amount, account=None):
        # 此方法为了实现根据类型，而改变所生成的日记账的科目
        # 我改造了account.payment的post()和_create_payment_entry()方法，
        # 为这两个方法添加了额外的参数，以达到在account.move过账之前实现科目的改动，
        # 相关的改变写在sale_extension/loan.py中
        record = self
        payment_obj = self.env['account.payment']
        total = payment_amount
        payment_methods = (total > 0) and self.statement_id.journal_id.inbound_payment_method_ids or \
                          self.statement_id.journal_id.outbound_payment_method_ids
        create_dict = {
            'payment_method_id': payment_methods and payment_methods[0].id or False,
            'payment_type': payment_type,
            'partner_id': record.partner_id and record.partner_id.id or False,
            'partner_type': partner_type,
            'journal_id': self.statement_id.journal_id.id,
            'payment_date': record.date,
            'state': 'draft',
            'currency_id': self.statement_id.journal_id.currency_id.id or self.statement_id.company_id.currency_id.id,
            'amount': abs(total),
            'communication': record._get_communication(payment_methods[0] if payment_methods else False),
            'name': self.statement_id.name,
            'company_id': self.statement_id.journal_id.company_id.id,
            'destination_journal_id': account and self.statement_id.journal_id.id,
            'destination_account_id': account and account.id
        }
        pay_obj = payment_obj.create(create_dict)
        if account:
            pay_obj.destination_account_id = account.id
        # 调取原生收款单，完成方法
        pay_obj.post(statement_line=self)
        # 回写数据，将收款单的日记账和当前数据关联
        pay_obj.move_line_ids.write({
            'statement_line_id': record.id,
            'statement_id': self.statement_id.id,
            'employee_id': record.employee_id.id
        })
        # if record.statement_class.name in [u'手续费', u'利息', u'其它']:
        # if record.statement_class.name:
        #     if record.amount > 0:
        #         fun = lambda r: r.credit > 0
        #     else:
        #         fun = lambda r: r.debit > 0
        #     move_line = pay_obj.move_line_ids.filtered(fun)
        #     move_line.write({
        #         'name': record.statement_class.name
        #     })
        for line in pay_obj.move_line_ids:
            ref = line.move_id.ref
            line.name = ref

        # # 还要更新收款单的日记账的科目，该功能移动到了sale_extension/loan.py中去了
        # self._update_move_account(pay_obj)
        # 更新当前数据
        record.write({
            'move_name': pay_obj.move_name,
        })

    @api.onchange('statement_class')
    def _get_account_account(self):
        # 根据选择的类型，填充借贷科目
        for statement in self:
            if statement.statement_class:
                if statement.flag == 'debit':
                    statement.debit_account_id = statement.statement_class.account_id
                    statement.credit_account_id = False
                elif statement.flag == 'credit':
                    statement.credit_account_id = statement.statement_class.account_id
                    statement.debit_account_id = False

    def _update_move_account(self, pay_obj):
        # pay_obj: account.payment
        # 贷方为“银行”
        if self.flag == 'debit':
            debit_account_id = self.debit_account_id.id
            credit_account_id = self.journal_id.default_credit_account_id.id
        elif self.flag == 'credit':
            debit_account_id = self.journal_id.default_credit_account_id.id
            credit_account_id = self.credit_account_id.id

        # for line in pay_obj.move_line_ids:
        #     if line.debit > 0:
        #         if not debit_account_id:
        #             raise ValidationError('明细的记录的借方科目或日记账的贷方科目未正确设置')
        #         line.account_id = debit_account_id
        #     elif line.credit > 0:
        #         if not credit_account_id:
        #             raise ValidationError('明细的记录的贷方科目或日记账的贷方科目未正确设置')
        #         line.account_id = credit_account_id

    @api.multi
    def action_salesman_confirm_partner(self):
        self.ensure_one()
        self.write({
            'salesman_id': self.env.user.id,
            'salesman_date': datetime.now()
        })

    @api.multi
    def action_salesman_cancel_partner(self):
        self.ensure_one()
        self.write({
            'salesman_id': None,
            'salesman_date': None
        })


class AccountBankStatementLineClass(models.Model):
    _name = 'account.statement.line.class'

    name = fields.Char('类名', required=True)
    code = fields.Char('编号', unique=True)
    account_id = fields.Many2one('account.account', string='借贷科目',  index=True,
        ondelete="cascade", domain=[('deprecated', '=', False)])
    used = fields.Selection([
        ('debit', '借方'),
        ('credit', '贷方') ], required=True, string="此科目用于：")
    

# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
